#include <ostream>
#include "stdafx.h"
#include "../common/WindbgExt.h"
#include "../common/ScriptExtInterface.h"
#include <EXTERN.h>
#include <perl.h>
#include "perl_io_layer.h"

#if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
#define PERLMODEXPORT __declspec(dllexport)
#else
#if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY)
#define PERLMODEXPORT __attribute__ ((visibility("default")))
#else
#define PERLMODEXPORT
#endif
# endif

EXTERN_C void boot_DynaLoader(pTHX_ CV* cv);

EXTERN_C void xs_init(pTHX)
{
	const char *file = __FILE__;
	/* DynaLoader is a special case */
	newXS("DynaLoader::boot_DynaLoader", reinterpret_cast<XSUBADDR_t>(boot_DynaLoader), file);
}

WindbgExt *dbgengine = NULL;

EXTERN_C PERLMODEXPORT int XS_windbg_SetWindbgInterface(WindbgExt* iface)
{
	dbgengine = iface;
	return 0;
}

WindbgExt* STDMETHODCALLTYPE dbg()
{
	return dbgengine;
}

int PrintErr(const char* msg, int ret)
{
	if (dbgengine)
	{
		dbgengine->Err(msg);
		char buf[64];
		sprintf(buf, "Error code: 0x%08lX\n", ret);
		dbgengine->Err(buf);
	}
	return ret;
}

int PrintErr(const wchar_t* msg, int ret)
{
	if (dbgengine)
		dbgengine->ErrW(msg);
	return ret;
}

EXTERN_C PERLMODEXPORT int XS_windbg_RunScript(const char** params)
{
	PerlInterpreter *perlEngine = NULL;

	std::vector<const char*> argv;
	argv.push_back("windbg");
	argv.push_back(NULL);
	int argc = argv.size() - 1;
	char** env = NULL;
	char** pargv = const_cast<char**>(&argv.front());
	PERL_SYS_INIT3(&argc, &pargv, &env);

	argv.pop_back();
	for (const char *param = *params; param != NULL; param = *(++params))
		argv.push_back(param);
	argv.push_back(NULL);
	argc = argv.size() - 1;
	pargv = const_cast<char**>(&argv.front());

	perlEngine = perl_alloc();
	perl_construct(perlEngine);
	perlEngine->Iexit_flags |= PERL_EXIT_DESTRUCT_END;
	perlEngine->Iperl_destruct_level = 1;
	perl_parse(perlEngine, xs_init, argc, pargv, env);
	PatchPerlIoLayer(perlEngine);
	perl_run(perlEngine);
	perl_destruct(perlEngine);
	perl_free(perlEngine);
	FlushIo();
	PL_curinterp = NULL;
	PERL_SYS_TERM();
	return 0;
}


BOOL APIENTRY DllMain(HANDLE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
		break;
	case DLL_THREAD_ATTACH:
		break;
	case DLL_THREAD_DETACH:
		break;
	case DLL_PROCESS_DETACH:
		break;
	}
	return TRUE;
}


